Conversation
|
Comparison scripts Vanilla FMEimport os
from pathlib import Path
from huggingface_hub import snapshot_download
from fme.coupled.inference.inference import main
import torch
import numpy as np
torch.manual_seed(0)
np.random.seed(0)
# ---------------------------------------------------------------------------
# Configuration
# ---------------------------------------------------------------------------
HF_REPO = "allenai/SamudrACE-CM4-piControl"
CACHE_DIR = str(Path.cwd() / "fme_cache")
# Number of coupled steps (each = 20 atm 6h steps + 1 ocean 5-day step)
N_COUPLED_STEPS = 4
OUTPUT_DIR = os.path.abspath("outputs/fme_reference_output")
print("Downloading SamudrACE files from HuggingFace...")
repo_dir = snapshot_download(repo_id=HF_REPO, cache_dir=CACHE_DIR)
print(f" Local repo: {repo_dir}")
# The YAML uses relative paths, so we chdir into the snapshot directory.
original_cwd = os.getcwd()
os.chdir(repo_dir)
print(f"Running coupled inference ({N_COUPLED_STEPS} coupled steps)...")
main(
yaml_config="inference_config.yaml",
override_dotlist=[
f"n_coupled_steps={N_COUPLED_STEPS}",
f"coupled_steps_in_memory={min(N_COUPLED_STEPS, 20)}",
f"experiment_dir={OUTPUT_DIR}",
],
)
os.chdir(original_cwd)
print(f"\nResults saved to {OUTPUT_DIR}/")
print("Done.")E2Simport earth2studio.run as run
from earth2studio.data.samudrace import SamudrACEData
from earth2studio.io import NetCDF4Backend
from earth2studio.models.px import SamudrACE
import torch
import numpy as np
torch.manual_seed(0)
np.random.seed(0)
SCENARIO = "0311"
N_COUPLED_STEPS = 4
N_INNER_STEPS = 20 # 20 atm 6h steps per coupled step
TOTAL_ATM_STEPS = N_COUPLED_STEPS * N_INNER_STEPS # 40 steps
# Use a proxy time that maps to Jan 1 for forcing lookup (day-of-year matching)
TIME = ["2000-01-01T00:00:00"]
OUTPUT_FILE = "outputs/e2s_reference_output.nc"
print("Loading SamudrACE via Earth2Studio...")
package = SamudrACE.load_default_package()
model = SamudrACE.load_model(package, forcing_scenario=SCENARIO)
data = SamudrACEData(ic_timestamp=f"{SCENARIO}-01-01T00:00:00")
print(f"Running deterministic forecast ({TOTAL_ATM_STEPS} steps)...")
io = run.deterministic(
time=TIME,
nsteps=TOTAL_ATM_STEPS,
prognostic=model,
data=data,
io=NetCDF4Backend(file_name=OUTPUT_FILE, backend_kwargs={"mode": "w"}),
)
print(f"\nResults saved to {OUTPUT_FILE}")
print("Done.") |
Greptile SummaryThis PR adds The implementation is well-structured and follows Earth2Studio conventions. Most of the prior review concerns have been addressed or acknowledged by the author. Key observations:
|
| Filename | Overview |
|---|---|
| earth2studio/models/px/samudrace.py | Core 954-line coupled atmosphere-ocean wrapper; logic is sound. Minor P2 concerns: __call__ always resets coupling state, and private FME attribute access (_input_only_names) creates fragile coupling. |
| earth2studio/data/samudrace.py | IC data source; lazy xarray operations before cache cleanup (non-cache path) is a known concern tracked in previous threads. |
| earth2studio/lexicon/samudrace.py | Clean bidirectional mapping between E2S and FME variable names; covers atmosphere (CM4 levels), ocean (CMIP6), and forcing variables. |
| pyproject.toml | Adds samudrace extra with fme>=2025.10.0; missing conflict declaration with ace2 (which also requires fme, unversioned). |
| earth2studio/io/netcdf4.py | Extends units_map with ns/us/ms time-unit entries needed for higher-resolution timedelta64 coordinates; safe additive change. |
Reviews (2): Last reviewed commit: "Greptile" | Re-trigger Greptile
|
@greptile-ai |





Earth2Studio Pull Request
Description
SamudrACEprognostic model wrapper that couples the ACE2 atmosphere model with the Samudra ocean model via FME'sCoupledStepper, enabling coupled climate inference through Earth2Studio's standardrun.deterministicworkflowSamudrACEDatadata source for fetching initial conditions andSamudrACELexiconfor variable name mapping between E2S and FME conventionssamudraceoptional dependency group (fme>=2025.10.0,pandas,scipy) with conflict declarations against atlas/fcn3/perturbation/sfno extrasPoints for discussion
I believe I found the source of the delta, seems the land sea mask has 1 ULP difference which apparently has a some slight difference with how its loaded. Seems the ocean model is very sensitive to the mask. I checked the input tensors of all other values and this was the only delta. I'm calling it within machine precision.
Modified Files
earth2studio/data/__init__.py,earth2studio/lexicon/__init__.py,earth2studio/models/px/__init__.py— Register new classesearth2studio/lexicon/base.py— Add ocean/coupled variable entries toE2STUDIO_VOCABearth2studio/data/ace2.py— Minor docstring line wrappingpyproject.toml— Addsamudraceoptional extra with conflict declarationstox.ini— Add samudrace tests to thetest-px-models-ace2environmentdocs/modules/models_px.rst— Add SamudrACE to prognostic model docs indexCHANGELOG.md— Add entryChecklist
Dependencies